package com.dhz.common.web.exception;

import com.alibaba.fastjson.JSON;
import com.dhz.common.base.Code;
import com.dhz.common.base.ServiceResult;
import com.dhz.common.base.SysCode;
import com.dhz.common.exception.GenericException;
import com.dhz.common.web.utils.Servlets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 系统异常统一处理类
 */
public class ExceptionHandler extends AbstractHandlerExceptionResolver {
    private static final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);

    /**
     * <p>系统异常统一处理类，与{@link com.dhz.common.web.controller.BaseRestController#handlerException(HttpServletRequest, Exception)} 一起完成；
     * 如果这两个地方都不能正确处理，则异常将会交由web.xml中的配置处理</p>
     *
     * 不能捕获的Spirng MVC异常类型列表，均交由{@link com.dhz.common.web.controller.BaseRestController#handlerException(HttpServletRequest, Exception)}处理：
     * <ul>
     *     <li>1. {@link BindException}</li>
     *     <li>2. {@link TypeMismatchException}</li>
     *     <li>3. {@link MissingServletRequestParameterException}</li>
     *     <li>4. -- </li>
     * </ul>
     *
     * @param request 请求对象
     * @param response 相应对象
     * @param o --
     * @param e 异常实例
     * @return 根据异常类型，返回对应的ServiceCode - {@link Code}
     */
    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {

        ModelAndView mv = new ModelAndView();

        // 异步记录日志
        // SpringUtils.getBean(AsyncLogQueue.class).post(new AsyncLogEvent.EventDataSysErr(httpServletRequest.getRequestURI(), Servlets.getRequestParams(request), e));
        logger.error("请求接口 ==> {}\n请求参数 ==> {}", request.getRequestURI(), JSON.toJSONString(Servlets.getRequestParams(request)), e);

        // 异常类型判断，返回不同的错误代码
        // 1.业务自定义的异常
        if (e instanceof GenericException) {
            mv.addObject(new ServiceResult(((GenericException) e).getCode(), e.getMessage()));
        }
        // n.未知异常
        else {
            mv.addObject(new ServiceResult(SysCode.ERR_SERVER));
        }

        return mv;

    }
}
